package chapter1_3_wait_notify;

import java.util.ArrayDeque;
import java.util.Queue;

/**
 * 当一个线程调用一个共享变量的wa i t（）方法时， 该调用线程会被阻塞挂起， 直到发生
 * 下面几件事情之一才返回：
 * (1 ） 其他线程调用了该共享对象的noti fy （）或者noti fy All （） 方法；
 * ( 2 ）其他线程调用了该线程的int err upt（） 方法， 该线程抛出InterruptedExce ption 异常返回。
 *
 * 另外需要注意的是，如果调用wait（） 方法的线程没有事先获取该对象的监视器锁，
 * 则调用wa it （） 方法时调用线程会抛出IllegalMonitorState Exce ption 异常。
 *
 * @author huayuhao
 * @date 2020/12/15 14:47
 */
public class WaitAndNotify {


    static class Producer extends Thread {

        String name;
        final Queue<Integer> queue;

        Producer(String name, Queue<Integer> queue) {
            this.name = name;
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    synchronized (queue) {
                        int maxSize = 10;
                        while (queue.size() >= maxSize) {
                            queue.wait();
                        }
                        queue.add(5);
                        System.out.println(Thread.currentThread().getName() + "生产了1个, 现在有" + queue.size());
                        Thread.sleep(100);
                        queue.notifyAll();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer extends Thread {

        String name;
        private final Queue<Integer> queue;

        Consumer(String name, Queue<Integer> queue) {
            this.name = name;
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    synchronized (queue) {
                        while (queue.size() == 0) {
                            queue.wait();
                        }
                        queue.remove();
                        System.out.println(this.name + " 消费了1个, 还剩:" + queue.size());
                        queue.notifyAll();
                        Thread.sleep(100);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new ArrayDeque<>();
        for (int i = 0; i < 3; i++) {
            Consumer c= new Consumer("consumer-" + i,queue);
            c.start();
        }

        for (int i = 0; i < 3; i++) {
            Producer p = new Producer("producer-" + i,queue);
            p.start();
        }
    }
}
